/*
 * Copyright (C) 2012 rothens
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package rpg.maps;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.imageio.ImageIO;
import rpg.Location;
import rpg.entities.Entity;
import rpg.entities.EntityHandler;
import rpg.gfx.light.LightSource;

/**
 *
 * @author rothens
 */
public class Map {

    public static final int LEFT = 0; //1
    public static final int UP = 1; //2
    public static final int RIGHT = 2; //4
    public static final int DOWN = 3; //8
    public static final int UPLEFT = 4;  //16
    public static final int UPRIGHT = 5; //32
    public static final int DOWNRIGHT = 6;  //64
    public static final int DOWNLEFT = 7;  //128
    private final String mapName;
    int width;
    int height;
    public MapTile[] tiles;
    public List<Entity> entities = new ArrayList<Entity>();
    public MapHandler mapHandler;
    public List<LightSource> lightSources = new ArrayList<LightSource>();
    Location spawn = null;

    public Map(String name, int width, int height, String mapdata, String layer1data, String layer2data, String roadData, String entityData, MapHandler mapHandler) {
        this.mapName = name;
        this.width = width;
        this.height = height;
        this.mapHandler = mapHandler;


        processMap(mapdata);
        processLayer1(layer1data);
        processLayer2(layer2data);
        processRoads(roadData);
        processEntities(entityData);
        calculateAutoTiles();
        //saveMinimap();
    }

    public void saveMinimap() {
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        BufferedImage big = new BufferedImage(width*2, height*2, BufferedImage.TYPE_INT_RGB);
        BufferedImage vbig = new BufferedImage(width*8, height*8, BufferedImage.TYPE_INT_RGB);
        int i = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                img.setRGB(x, y, tiles[i].getMapcolor());
                i++;
            }
        }
        for(int y = 0; y < height*2; y++){
            for(int x = 0; x < width*2; x++) {
                MapTile mt = tiles[(y/2)*width+(x/2)];
                big.setRGB(x, y, mt.getBigMapColor(y%2*2 + x%2));
            }
        }
        for(int y = 0; y < height*8; y++){
            for(int x = 0; x < width*8; x++) {
                MapTile mt = tiles[(y/8)*width+(x/8)];
                vbig.setRGB(x, y, mt.getVeryBigMapColor(y%8*8 + x%8));
            }
        }
        
        
        File f = new File("./"+mapName+".png");
        File f2 = new File("./"+mapName+"_big.png");
        File f3 = new File("./"+mapName+"_vbig.png");
        try {
            ImageIO.write(img, "png", f);
            ImageIO.write(big, "png", f2);
            ImageIO.write(vbig, "png", f3);
        } catch (Exception e){
            
        }
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    private void processMap(String data) {
        int i = 0;
        tiles = new MapTile[width * height];
        for (char c : data.toCharArray()) {
            tiles[i] = new MapTile(MapHandler.tileset.getTile(c));
            i++;
            if (i == width * height) {
                break;
            }
        }
        if (i < width * height - 1) {
            for (; i < width * height; i++) {
                tiles[i] = new MapTile(MapHandler.tileset.getTile('~'));
            }
        }
    }

    private void processLayer1(String layer1data) {
        int i = 0;

        for (char c : layer1data.toCharArray()) {
            if (c == '.') {
                i++;
                continue;
            }
            if (c == '*' && spawn == null) {
                spawn = new Location(i, this);
                //Player.newInstance(spawn, Game.getInstance());
                //System.out.println("playerNewInstance");
            }
            tiles[i].setLayer1(MapHandler.tileset.getLayer1(c));
            i++;
            if (i == width * height) {
                break;
            }
        }
        if (i < width * height - 1) {
            for (; i < width * height; i++) {
                tiles[i].setLayer1(null);
            }
        }
    }

    private void processLayer2(String layer2data) {
        int i = 0;

        for (char c : layer2data.toCharArray()) {
            if (c == '.') {
                i++;
                continue;
            }
            tiles[i].setLayer2(MapHandler.tileset.getLayer2(c));
            i++;
            if (i == width * height) {
                break;
            }
        }
        if (i < width * height - 1) {
            for (; i < width * height; i++) {
                tiles[i].setLayer2(null);
            }
        }
    }

    private void processRoads(String roadData) {
        int i = 0;

        for (char c : roadData.toCharArray()) {
            if (c == '.') {
                i++;
                continue;
            }
            try {
                tiles[i].setRoad((Tiles.RoadTile) MapHandler.tileset.getRoad(c).clone());
            } catch (Exception ex) {
            }
            i++;
            if (i == width * height) {
                break;
            }
        }
        if (i < width * height - 1) {
            for (; i < width * height; i++) {
                tiles[i].setRoad(null);
            }
        }

        for (i = 0; i < width * height; i++) {
            Tiles.RoadTile act = tiles[i].getRoad();
            if (act == null) {
                continue;
            }
            int val = 0;
            for (int j = 0; j < 4; j++) {
                Tiles.RoadTile toCheck = getRoadTile(i, j, this);
                if (toCheck == null) {
                    continue;
                }
                if (act.getName() == toCheck.getName()) {
                    val += Math.pow(2, j);
                }
            }
            act.setState(val);

        }

    }

    private void calculateAutoTiles() {
        for (int i = 0; i < width * height; i++) {
            HashMap<Character, AutoTileData> atiles = new HashMap<Character, AutoTileData>();
            for (int j = 0; j < 8; j++) {

                MapTile mt = mapHandler.getTile(i, j, this);
                if (mt.getLandscape().precedence > tiles[i].getLandscape().precedence && mt.getLandscape().autoTile) {
                    AutoTileData ad = atiles.get(mt.getLandscape().name);
                    if (ad == null) {
                        ad = new AutoTileData(0, 0, mt.getLandscape().name);
                    }
                    if (j < 4) {
                        ad.side += 0x1 << j;

                    } else {
                        ad.corner += 0x1 << (j - 4);
                    }
                    atiles.put(mt.getLandscape().name, ad);
                }
            }
            for (AutoTileData ad : atiles.values()) {
                tiles[i].addAutoData(ad);

            }
            tiles[i].generateOverImage();
        }
    }

    public boolean isPassableEntity(int tileLoc) {

        /*
         * Jelenleg minden Sprite passable
         */

        for (Entity e : entities) {
            Location l = e.getCurrentLocation();
            if (l.getMapCoordinate() == tileLoc) {
                if (!e.isPassable()) {
                    return false;
                }
            }
        }
        return true;
    }

    public List<Entity> getEntity(int tileLoc, int playerLoc) {
        List<Entity> ret = new ArrayList<Entity>();
        for (Entity e : entities) {
            Location l = e.getCurrentLocation();
            if (tileLoc > playerLoc) {
                if (l.getMapCoordinate(l) <= tileLoc && l.getMapCoordinate(l) > playerLoc) {
                    ret.add(e);
                }
            } else {
                if (l.getMapCoordinate(l) >= tileLoc && l.getMapCoordinate(l) < playerLoc) {
                    ret.add(e);
                }
            }
        }
        return ret;
    }

    private void processEntities(String entityData) {
        int i = 0;
        for (char c : entityData.toCharArray()) {
            if (c == '.') {
                i++;
                continue;
            }
            Entity entity = EntityHandler.getInstance().createEntity(c, new Location(i, this));
            if (entity != null) {
                entities.add(entity);
            }
            i++;
            if (i == width * height) {
                break;
            }
        }

    }

    private Tiles.RoadTile getRoadTile(int actual, int dir, Map map) {
        switch (dir) {
            case UP:
                if (actual - map.width < 0) {
                    return null;
                }
                return map.tiles[actual - map.width].getRoad();
            case LEFT:
                if (actual % map.width == 0) {
                    return null;
                }
                return map.tiles[actual - 1].getRoad();
            case DOWN:
                if (actual + map.width >= map.width * map.height) {
                    return null;
                }
                return map.tiles[actual + map.width].getRoad();
            case RIGHT:
                if (actual % map.width == map.width - 1) {
                    return null;
                }
                return map.tiles[actual + 1].getRoad();
        }
        return null;
    }

    public String getMapName() {
        return mapName;
    }
}
